package com.cloudkinto.service.user.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.cloudkinto.appletservice.user.vo.AppletUserLoginSuccessRes;
import com.cloudkinto.common.DicBusinessConstant;
import com.cloudkinto.common.DicBusinessItemConstant;
import com.cloudkinto.common.common.HttpUtil;
import com.cloudkinto.common.common.MD5Util;
import com.cloudkinto.common.common.PersonalInfoUtils;
import com.cloudkinto.common.common.VerificationCodeUtil;
import com.cloudkinto.common.constant.GlobalConstants;
import com.cloudkinto.common.constant.SysConstant;
import com.cloudkinto.common.exception.BizException;
import com.cloudkinto.common.exception.BizExceptionI18;
import com.cloudkinto.common.utils.*;
import com.cloudkinto.common.web.PageResult;
import com.cloudkinto.common.web.SingleResult;
import com.cloudkinto.dao.*;
import com.cloudkinto.entity.*;
import com.cloudkinto.service.email.MailSenderService;
import com.cloudkinto.service.file.FileService;
import com.cloudkinto.service.order.OrderTiktokService;
import com.cloudkinto.service.order.vo.TiktokOrderVO;
import com.cloudkinto.service.order.vo.yahoo.YahooUserInfo;
import com.cloudkinto.service.role.RoleService;
import com.cloudkinto.service.shop.ShopService;
import com.cloudkinto.service.user.UserService;
import com.cloudkinto.service.user.captchamode.CaptchaModeService;
import com.cloudkinto.service.user.captchamode.Context;
import com.cloudkinto.service.user.captchamode.impl.MailSendMsgImpl;
import com.cloudkinto.service.user.captchamode.impl.PhoneSendMsgImpl;
import com.cloudkinto.service.user.vo.*;
import com.cloudkinto.session.UserSession;
import com.cloudkinto.session.UserSessionException;
import com.cloudkinto.session.UserSessionManager;
import com.cloudkinto.utils.CustomApiClient;
import com.cloudkinto.utils.YahooUtils;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.gson.Gson;
import com.google.gson.JsonObject;
import lombok.extern.slf4j.Slf4j;
import okhttp3.*;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.SystemUtils;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.util.EntityUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.ResponseEntity;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.client.RestTemplate;
import tiktokshop.open.sdk_java.api.AuthorizationV202309Api;
import tiktokshop.open.sdk_java.api.OrderV202309Api;
import tiktokshop.open.sdk_java.invoke.ApiException;
import tiktokshop.open.sdk_java.model.Authorization.V202309.GetAuthorizedShopsResponse;
import tiktokshop.open.sdk_java.model.Authorization.V202309.GetAuthorizedShopsResponseData;
import tiktokshop.open.sdk_java.model.Authorization.V202309.GetAuthorizedShopsResponseDataShops;
import tiktokshop.open.sdk_java.model.Order.V202309.*;

import javax.net.ssl.SSLContext;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.net.SocketException;
import java.net.URLEncoder;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import static com.cloudkinto.common.constant.GlobalConstants.*;

/**
 * <p>
 * service实现类
 * </p>
 *
 * @author 张永远
 * @since 2020-05-27
 */
@Service
@Transactional(rollbackFor = Exception.class)//事务回滚
@Slf4j
public class UserServiceImpl extends ServiceImpl<UserDao, UserDo> implements UserService {
    private final RestTemplate restTemplate = new RestTemplate();
    private static final String AUTHORIZESTATEKEY = "oms_authorize_key";
    private final String redirectUri = "https://www.cloudkinto.com/kinto/KeyBinding";
    private final String yahooScope = "openid profile email address ";
    private final String YAHOOACCESSTOKEN_USER = "YAHOOACCESSTOKEN_USER_";//用户访问令牌(短期)(1小时)
    private final String YAHOOREFRESH_TOKEN_USER = "YAHOOREFRESH_TOKEN_USER_";//用户刷新令牌(长期)(4周)
    private String YAHOOAUTHORIZESTATEKEY = "yahoo_authorize_state_";
    @Autowired
    private TiktokOrderDao  tiktokOrderDao;
    @Autowired
    private TiktokOrderPackageDao  tiktokOrderPackageDao;
    @Autowired
    private  TiktokOrderLineItemDao tiktokOrderLineItemDao;

    private final String orderYahooSign = "orderYahooSignList";
    @Value("${gbc.login.verificationCode}")
    private boolean verificationCode;
    @Value("${tiktok.client.id}")
    private String clientId;
    @Value("${tiktok.client.secret}")
    private String clientSecret;
    @Value("${tiktok.client.app-key}")
    private String appKey;
    @Value("${gbc.scheduling}")
    private String type;
    @Autowired
    private UserDao dao;
    @Autowired
    private FileService fileService;
    @Autowired
    private CompanyDao companyDao;
    @Autowired
    private CompanyAuthorizeDao companyAuthorizeDao;
    @Autowired
    private FileDao fileDao;
    @Autowired
    private RoleDao roleDao;
    @Autowired
    private MenuDao menuDao;
    @Autowired
    private RoleService roleService;
    @Autowired
    private ShopDao shopDao;
    @Autowired
    private ShopService shopService;
    @Autowired
    private DicBusinessItemDao dicBusinessItemDao;
    @Autowired
    private UserSessionManager userSessionManager;
    @Autowired
    private RoleMenuRelationDao roleMenuRelationDao;
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private MailSenderService mailSenderService;
    @Autowired
    private ThreadPoolTaskExecutor threadPoolTaskExecutor;
    @Autowired
    private WxUserDao wxUserDao;
    @Autowired
    private OrderTiktokService orderTiktokService;

    private String AMZACCESSTOKEN = "AMZACCESSTOKEN:";
    private String STSSESSIONTOKEN = "STSSESSIONSTOKEN";

    @Override
    public void test() {
        UserSession session = new UserSession();
        session.setSessionId(UUID.randomUUID().toString());
//        session.setUserId(userDo.getId());
//        session.setCompanyId(userDo.getCompanyId());
//        session.setShopId(userDo.getShopId());
//        session.setStorageId(userDo.getStorageId());
        redisTemplate.opsForValue().set("USER_SESSION_TOKEN:" + session.getSessionId(), JSONObject.toJSONString(session), 3600, TimeUnit.SECONDS);
    }

    @Override
    public UserLoginSuccessRes login(UserLoginReq req, HttpServletRequest request) {
        //校验验证码
        if (verificationCode) {
            String verificationCode = (String) redisTemplate.opsForValue().get("verificationCode:" + req.getKey());
            if (StringUtils.isBlank(verificationCode)) {
                throw new BizExceptionI18(SysConstant.Login_VerCode_Expired);
            } else if (!(verificationCode.equals(req.getVerificationCode()))) {
                throw new BizExceptionI18(SysConstant.Login_VerCode_InCorrect);
            }
        }
        MD5Util md5 = new MD5Util(SysConstant.SALT_STRING, "MD5");

        LambdaQueryWrapper<UserDo> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(UserDo::getUserAccount, req.getUserAccount())
                .eq(UserDo::getUserPassword, md5.encode(req.getUserPassword()))
                .eq(UserDo::getUserRoleType, 0)
                .eq(UserDo::getUserType, 1);
        UserDo userDo = this.baseMapper.selectOne(wrapper);
        if (userDo == null) {
            // Object o = redisTemplate.opsForValue().get("passwordError_" + req.getUserAccount());
            // redisTemplate.opsForValue().set("passwordError_" + req.getUserAccount(), o == null ? 1 : Integer.parseInt(o.toString()) + 1);
            // if (o == null || Integer.parseInt(o.toString()) < 5) {
                throw new BizExceptionI18(SysConstant.Login_Error_AccountPassword);
            // } else {
            //     throw new BizException("密码输入错误5次,账号已被锁定，请联系管理员");
            // }
        } else if (userDo.getUserStatus() != 1) {
            throw new BizExceptionI18(SysConstant.Login_Error_Checking);
        }
        redisTemplate.delete("passwordError_" + req.getUserAccount());

        //创建会话
        UserSession session = userSessionManager.createSession(userDo);

        UserLoginSuccessRes res = new UserLoginSuccessRes();
        res.setUserId(session.getUserId());
        res.setSessionId(session.getSessionId());
        res.setUserAccount(userDo.getUserAccount());
        res.setUserName(userDo.getUserName());
        res.setHeadUrl(fileService.getFilePath(userDo.getHeadFileId()));
        res.setMenuTree(roleService.getMenuTree(userDo.getRoleId(), req.getLanguage(), userDo.getCompanyId()));
        res.setButton(menuDao.getButton(userDo.getRoleId()));
        //登录成功 session域中改变登陆人
        request.getSession().setAttribute(UserSession.SESSION_ID_KEY, session);

        LambdaUpdateWrapper<UserDo> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(UserDo::getId, userDo.getId());
        updateWrapper.set(UserDo::getLastLoginTime, new Date());
        this.update(updateWrapper);
        return res;
    }

    @Override
    public UserLoginSuccessRes main(String token, String lang) {
        UserSession session = userSessionManager.getSession(token);
        if (session == null) throw new UserSessionException();
        UserLoginSuccessRes res = new UserLoginSuccessRes();
        UserDo userDo = dao.selectById(session.getUserId());
        if (userDo == null) throw new BizExceptionI18(SysConstant.Login_Error_Notfound);
        res.setUserId(session.getUserId());
        res.setSessionId(session.getSessionId());
        res.setUserAccount(userDo.getUserAccount());
        res.setUserName(userDo.getUserName());
        res.setHeadUrl(fileService.getFilePath(userDo.getHeadFileId()));
        res.setMenuTree(roleService.getMenuTree(userDo.getRoleId(), (lang != null && lang.equals("jp")) ? 2 : 1, userDo.getCompanyId()));
        res.setButton(menuDao.getButton(userDo.getRoleId()));
        return res;
    }

    @Override
    public SingleResult getToken(String username, String password, HttpServletRequest request) {
//        MD5Util md5 = new MD5Util(SysConstant.SALT_STRING, "MD5");
        if (StringUtils.isBlank(username)) {
            throw new BizExceptionI18(SysConstant.Login_Error_No_Username);
        }
        if (StringUtils.isBlank(password)) {
            throw new BizExceptionI18(SysConstant.Login_Error_No_Password);
        }
        LambdaQueryWrapper<UserDo> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(UserDo::getUserAccount, username)
                .eq(UserDo::getUserPassword, password)
                .eq(UserDo::getUserType, 1);
        UserDo userDo = this.baseMapper.selectOne(wrapper);
        if (userDo == null) {
            throw new BizExceptionI18(SysConstant.Login_Error_AccountPassword);
        } else if (userDo.getUserStatus() != 1) {
            throw new BizExceptionI18(SysConstant.Login_Error_Checking);
        }
//        if (userDo.getCompanyId() == 510L) {
        String sessionKey = "sessionKey_temp_" + userDo.getId();
        if (redisTemplate.hasKey(sessionKey)) {
            String sessionId = (String) redisTemplate.opsForValue().get(sessionKey);
            request.getSession().setAttribute(UserSession.SESSION_ID_KEY, userSessionManager.getSession(sessionId));
            return SingleResult.success(sessionId);
        } else {
            //创建会话
            UserSession session = userSessionManager.createSession(userDo, true);
            //登录成功 session域中改变登陆人
            request.getSession().setAttribute(UserSession.SESSION_ID_KEY, session);
            redisTemplate.opsForValue().set(sessionKey, session.getSessionId(), 36000, TimeUnit.SECONDS);
            return SingleResult.success(session.getSessionId());
        }
//        }
//        //创建会话
//        UserSession session = userSessionManager.createSession(userDo, true);
//        //登录成功 session域中改变登陆人
//        request.getSession().setAttribute(UserSession.SESSION_ID_KEY, session);
//        return SingleResult.success(session.getSessionId());
    }

    @Override
    public SingleResult getTokenApplet(String username, String password, HttpServletRequest request) {
        MD5Util md5 = new MD5Util(SysConstant.SALT_STRING, "MD5");

        LambdaQueryWrapper<UserDo> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(UserDo::getUserAccount, username)
                .eq(UserDo::getUserPassword, md5.encode(password))
                .eq(UserDo::getUserType, 1);
        UserDo userDo = this.baseMapper.selectOne(wrapper);
        if (userDo == null) {
            throw new BizExceptionI18("account.password.error");
        } else if (userDo.getUserStatus() != 1) {
            throw new BizExceptionI18("account.checking");
        }

        // 创建会话
        UserSession session = userSessionManager.createSession(userDo);
        AppletUserLoginSuccessRes res = new AppletUserLoginSuccessRes();
        res.setUserId(session.getUserId());
        res.setSessionId(session.getSessionId());
        res.setUserAccount(userDo.getUserAccount());
        res.setUserName(userDo.getUserName());
        res.setUserRoleType(userDo.getUserRoleType());
        res.setHeadUrl(fileService.getFilePath(userDo.getHeadFileId()));

        // 验证 userRoleType 是否为后台用户
        if (!isBackendUser(userDo.getUserRoleType())) {
            throw new BizExceptionI18("no.backend.access");
        }

        return SingleResult.success(session.getSessionId());
    }

    @Override
    public SingleResult getTokenLabella(String username, String password, HttpServletRequest request) {
        //创建会话
        if (!"donghailongwang".equals(username) || !"258369".equals(password)) {
            return SingleResult.success();
        }
        UserSession session = userSessionManager.createSession(591L);
        //登录成功 session域中改变登陆人
        request.getSession().setAttribute(UserSession.SESSION_ID_KEY, session);
        return SingleResult.success(session.getSessionId());
    }


    private boolean isBackendUser(Integer userRoleType) {
        // 假设后台用户的 userRoleType 为 2
        return userRoleType == 2;
    }

    @Override
    public void logout(String token) {
        userSessionManager.clearSession(token);
    }

    @Override
    public UserRegisterReq register(UserRegisterReq req) {
        checkRegister(req);

        if (req.getCompanyFileId() != null) {
            fileService.uploadFile(req.getCompanyFileId());
        }

        CompanyDo companyDo = new CompanyDo();
        companyDo.setName(req.getCompanyName());
        companyDo.setFileId(req.getCompanyFileId());
        companyDo.setCreateTime(new Date());
        companyDo.setDeleteFlag(SysConstant.DELETE_FLAG_FALSE);
        companyDao.insert(companyDo);
        companyDo.setCompanyCode(OrderCodeUtil.generateCompanyCode(companyDo.getId()));
        companyDao.updateById(companyDo);

        MD5Util md5 = new MD5Util(SysConstant.SALT_STRING, "MD5");

        UserDo userDo = new UserDo();
        userDo.setUserPassword(md5.encode(req.getUserPassword()));
        userDo.setUserAccount(req.getUserAccount());
        userDo.setUserName(req.getUserName());
        userDo.setUserMail(req.getUserMail());
        userDo.setUserPhone(req.getUserPhone());
        userDo.setCompanyId(companyDo.getId());
        userDo.setUserStatus(0);
        userDo.setUserType(1);
        userDo.setCreateTime(new Date());
        userDo.setDeleteFlag(SysConstant.DELETE_FLAG_FALSE);
        //生成权限
        long id = this.createDefaultRole(companyDo.getId());
        userDo.setRoleId(id);
        dao.insert(userDo);
        threadPoolTaskExecutor.execute(() -> {
            mailSenderService.sendEmail("有新的客户注册", "名字：" + req.getUserName() + "<br />公司名称：" + req.getCompanyName() +
                    "<br />联系电话：" + req.getUserPhone() +
                    "<br />电子邮箱：" + req.getUserMail() + "<br />公司证件：" + fileService.getFilePath(req.getCompanyFileId()), SysConstant.cloudkintEmail);
        });
        return req;
    }


    /**
     * 给公司生成默认角色 和权限
     *
     * @param companyId
     * @return
     */
    public long createDefaultRole(Long companyId) {
        //创建公司默认角色
        List<RoleDo> roleDoList = roleDao.selectList(new LambdaQueryWrapper<RoleDo>().eq(RoleDo::getCompanyId, -1).isNotNull(RoleDo::getDevCode));
        long adminRoleId = 0;
        for (RoleDo role : roleDoList) {
            //先去判断有没有
            RoleDo et = roleDao.selectOne(new LambdaQueryWrapper<RoleDo>().eq(RoleDo::getCompanyId, companyId).eq(RoleDo::getDevCode, role.getDevCode()).last(" limit 1"));
            if (et == null) {
                et = new RoleDo();
                BeanUtils.copyProperties(role, et);
                et.setId(null);
                et.setRoleType(1);//前台用户
                et.setCompanyId(companyId);
                roleDao.insert(et);
                if (SysConstant.clientAdmin.equals(et.getDevCode())) {
                    adminRoleId = et.getId();
                }
                List<RoleMenuRelationDo> list = roleMenuRelationDao.selectList(new LambdaQueryWrapper<RoleMenuRelationDo>().eq(RoleMenuRelationDo::getRoleId, role.getId()));
                for (RoleMenuRelationDo roleMenuDo : list) {
                    RoleMenuRelationDo relationDo = new RoleMenuRelationDo();
                    relationDo.setRoleId(et.getId());
                    relationDo.setMenuId(roleMenuDo.getMenuId());
                    roleMenuRelationDao.insert(relationDo);
                }
            }
            //这个公司下的 用户 roleId 改成新的
            LambdaQueryWrapper<UserDo> userWrapper = new LambdaQueryWrapper<>();
            if (companyId == -1L) {
                userWrapper.isNull(UserDo::getCompanyId);
            } else {
                userWrapper.eq(UserDo::getCompanyId, companyId);
            }
            userWrapper.eq(UserDo::getRoleId, role.getId());
            List<UserDo> userDos = dao.selectList(userWrapper);
            for (UserDo userDo : userDos) {
                userDo.setRoleId(et.getId());
                dao.updateById(userDo);
            }
            if (SysConstant.clientAdmin.equals(et.getDevCode()) || SysConstant.serverAdmin.equals(et.getDevCode())) {
                //如果是管理员 则 给所有按钮加权限
                List<MenuDo> button = menuDao.selectList(new LambdaQueryWrapper<MenuDo>().eq(MenuDo::getType, 3).eq(MenuDo::getSystem, 0));
                for (MenuDo menuDo : button) {
                    RoleMenuRelationDo relationDo = roleMenuRelationDao.selectOne(new LambdaQueryWrapper<RoleMenuRelationDo>().eq(RoleMenuRelationDo::getMenuId, menuDo.getId())
                            .eq(RoleMenuRelationDo::getRoleId, et.getId()).last(" order by id desc limit 1"));
                    if (relationDo != null) {
                        continue;
                    }
                    relationDo = new RoleMenuRelationDo();
                    relationDo.setRoleId(et.getId());
                    relationDo.setMenuId(menuDo.getId());
                    roleMenuRelationDao.insert(relationDo);
                }
            }
        }
        return adminRoleId;
    }


    private void checkRegister(UserRegisterReq req) {
        LambdaQueryWrapper<UserDo> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(UserDo::getUserAccount, req.getUserAccount());
        int count = this.baseMapper.selectCount(wrapper);
        if (count > 0) {
            throw new BizExceptionI18(SysConstant.Login_Error_Existed);
        }
    }


    @Override
    public SingleResult bindKeyInit() {

        List<Map> platformList = new ArrayList<>();

        LambdaQueryWrapper<DicBusinessItemDo> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(DicBusinessItemDo::getDicBusinessId, DicBusinessConstant.platform);

        List<DicBusinessItemDo> itemDoList = dicBusinessItemDao.selectList(wrapper);
        List<DicBusinessItemDo> collect = itemDoList.stream().filter(dicBusinessItemDo -> dicBusinessItemDo.getDicBusinessId() != DicBusinessItemConstant.other).collect(Collectors.toList());
        if (CollectionUtils.isNotEmpty(collect)) {
            for (DicBusinessItemDo itemDo : collect) {
                Map map = new HashMap();
                map.put("platformId", itemDo.getId());
                map.put("value", itemDo.getDicItemValue());
                platformList.add(map);
            }
        }

        return SingleResult.success(platformList);
    }

    @Override
    public SingleResult keySecret(Long plantFormId, Long shopId) {
        Map map = new HashMap();
        ShopDo shopDo = shopDao.selectById(shopId);
        CompanyDo companyDo = companyDao.selectById(shopDo.getCompanyId());
        if (shopDo != null) {
            if (plantFormId.equals(DicBusinessItemConstant.amazon)) {
                map.put("key", shopDo.getAmazonSellerId());
                map.put("value", shopDo.getAmazonToken());
                map.put("keyName", "卖家账号");
                map.put("valueName", "访问token");
            } else if (plantFormId.equals(DicBusinessItemConstant.rakuton)) {
                map.put("key", shopDo.getRakutenLicense());
                map.put("value", shopDo.getRakutenSecret());
                map.put("keyName", "licenseKey");
                map.put("valueName", "服务秘钥（serviceSecret）");
            } else if (plantFormId.equals(DicBusinessItemConstant.qooTen)) {
                map.put("key", shopDo.getQootenKey());
                map.put("value", shopDo.getQootenPwd());
                map.put("id", shopDo.getQootenId());
                map.put("keyName", "秘钥");
                map.put("valueName", "密码");
                map.put("idName", "账号");
            }
            if (DicBusinessItemConstant.temu.intValue() == plantFormId.intValue()) {
                CompanyAuthorizeDo et = companyAuthorizeDao.selectOne(new LambdaQueryWrapper<CompanyAuthorizeDo>()
                        .eq(CompanyAuthorizeDo::getCompanyId, shopDo.getCompanyId())
                        .eq(CompanyAuthorizeDo::getShopId, shopId)
                        .eq(CompanyAuthorizeDo::getType, "temu")
                        .orderByDesc(CompanyAuthorizeDo::getId).last(" limit 1"));
                map.put("keyName", "货主ID");
                map.put("valueName", "授权码");
                if (et != null) {
                    map.put("key", et.getCompanyCode());
                    map.put("value", et.getAuthKey());
                    map.put("status", et.getActive());
                } else {
                    // map.put("status", "0");
                }
            }
        }
        return SingleResult.success(map);
    }

    @Override
    public SingleResult shopListFromPlantForm(Long plantFormId, Long companyId) {

        List<Map> shopList = new ArrayList<>();
        LambdaQueryWrapper<ShopDo> shopDoLambdaQueryWrapper = new LambdaQueryWrapper<>();
        shopDoLambdaQueryWrapper
//                .eq(ShopDo::getPlatformId, plantFormId)
                .eq(ShopDo::getCompanyId, companyId);
        List<ShopDo> shopDoList = shopDao.selectList(shopDoLambdaQueryWrapper);
        CompanyDo companyDo = companyDao.selectById(companyId);
        if (!CollectionUtils.isEmpty(shopDoList)) {
            for (ShopDo shopDo : shopDoList) {
                Map itemMap = new HashMap();
                itemMap.put("shopId", shopDo.getId());

                if (StringUtils.isNotBlank(shopDo.getYahooSellerId()))
                    itemMap.put("sellerId", shopDo.getYahooSellerId());
                itemMap.put("value", shopDo.getShopName());
                shopList.add(itemMap);
            }
        }
        if (DicBusinessItemConstant.Shopify.intValue() == plantFormId.intValue()) {
            Map itemMap = new HashMap();
            itemMap.put("shopId", null);
            itemMap.put("value", "作为新店铺添加");
            shopList.add(itemMap);
        }
        return SingleResult.success(shopList);
    }

    @Override
    public SingleResult addInit(Long companyId) {
        Map result = new HashMap();

        List<Map> roleList = new ArrayList<>();

        LambdaQueryWrapper<RoleDo> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(RoleDo::getCompanyId, companyId);
        List<RoleDo> roleDoList = roleDao.selectList(wrapper);
        if (CollectionUtils.isNotEmpty(roleDoList)) {
            for (RoleDo roleDo : roleDoList) {
                Map map = new HashMap();
                map.put("id", roleDo.getId());
                map.put("value", roleDo.getRoleName());
                map.put("code", roleDo.getDevCode());
                roleList.add(map);
            }
        }
        result.put("roleList", roleList);

        List<Map> shopList = new ArrayList<>();
        LambdaQueryWrapper<ShopDo> shopDoLambdaQueryWrapper = new LambdaQueryWrapper<>();
        shopDoLambdaQueryWrapper.eq(ShopDo::getCompanyId, companyId);
        List<ShopDo> shopDoList = shopDao.selectList(shopDoLambdaQueryWrapper);
        if (CollectionUtils.isNotEmpty(shopDoList)) {
            for (ShopDo shopDo : shopDoList) {
                Map map = new HashMap();
                map.put("id", shopDo.getId());
                map.put("value", shopDo.getShopName());
                shopList.add(map);
            }
        }
        result.put("shopList", shopList);
        return SingleResult.success(result);
    }

    @Override
    public UserBuildReq add(UserBuildReq req, Long userId, Long companyId) {
        addCheck(req);

        MD5Util md5 = new MD5Util(SysConstant.SALT_STRING, "MD5");

        UserDo entityDo = new UserDo();
        BeanUtils.copyProperties(req, entityDo);
        handlerAddBefore(entityDo, userId);

        entityDo.setUserPassword(md5.encode(req.getUserPassword()));
        entityDo.setUserStatus(1);
        entityDo.setUserType(1);
        entityDo.setShopId(req.getShopId());
        entityDo.setCompanyId(companyId);
        dao.insert(entityDo);
        return req;
    }

    //新增校验
    private void addCheck(UserBuildReq req) {
        LambdaQueryWrapper<UserDo> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(UserDo::getUserAccount, req.getUserAccount());
        int count = this.baseMapper.selectCount(wrapper);
        if (count > 0) {
            throw new BizExceptionI18(SysConstant.Login_Error_Existed);
        }
    }

    //做新增之前要执行的业务定制处理
    private void handlerAddBefore(UserDo entityDo, Long userId) {
        entityDo.setCreateBy(userId);
        entityDo.setCreateTime(new Date());
        entityDo.setDeleteFlag(SysConstant.DELETE_FLAG_FALSE);
    }


    @Override
    public SingleResult updateInit(Long id) {
        UserDo entityDo = dao.selectById(id);
        if (entityDo == null) {
            throw new BizExceptionI18(SysConstant.Login_Error_Notfound);
        }
        UserDetailRes res = new UserDetailRes();

        res.setId(entityDo.getId());
        res.setUserAccount(entityDo.getUserAccount());
        res.setUserName(entityDo.getUserName());
        res.setUserMail(entityDo.getUserMail());
        res.setUserPhone(entityDo.getUserPhone());
        res.setIsBinding(entityDo.getIsBinding());

        CompanyDo companyDo = companyDao.selectById(entityDo.getCompanyId());
        if (companyDo != null) {
            res.setCompanyName(companyDo.getName());
        }
        FileDo fileDo = fileDao.selectById(entityDo.getHeadFileId());
        if (fileDo != null) {
            res.setHeadFileUrl(fileService.getFilePath(fileDo.getId()));
            res.setHeadFileId(fileDo.getId());
            res.setFileName(fileDo.getFileName());
        }

        return SingleResult.success(res);
    }

    @Override
    public UserUpdateReq update(UserUpdateReq req, Long userId) {
        UserDo entityDo = dao.selectById(req.getId());

        if (req.getHeadFileId() != null) {
            fileService.deleteFile(entityDo.getHeadFileId());
            fileService.uploadFile2(req.getHeadFileId(), entityDo.getHeadFileId());
        }
        entityDo.setUserPhone(req.getUserPhone());
        entityDo.setUserMail(req.getUserMail());
        entityDo.setRoleId(req.getRoleId());
        entityDo.setShopId(req.getShopId());
        entityDo.setUserName(req.getUserName());
        entityDo.setHeadFileId(req.getHeadFileId());
        entityDo.setIsBinding(req.getIsBinding());
        handlerUpdateBefore(entityDo, userId);
        dao.updateById(entityDo);
        if (req.getShopId() == null) {
            LambdaUpdateWrapper<UserDo> shopDoLambdaQueryWrapper = new LambdaUpdateWrapper<>();
            shopDoLambdaQueryWrapper.set(UserDo::getShopId, null)
                    .eq(UserDo::getId, req.getId());
            this.update(shopDoLambdaQueryWrapper);
        }
        return req;
    }

    @Override
    public UpdatePasswordReq updatePassword(UpdatePasswordReq req, Long userId) {
        if (!req.getNewPassword().equals(req.getNewPasswordAgain())) {
            throw new BizExceptionI18(SysConstant.Login_Update_NotSame);
        }
        UserDo entityDo = dao.selectById(userId);
        MD5Util md5 = new MD5Util(SysConstant.SALT_STRING, "MD5");
        if (!(md5.encode(req.getPassword()).equals(entityDo.getUserPassword()))) {
            throw new BizExceptionI18(SysConstant.Login_Error_OldPass);
        }

        entityDo.setUserPassword(md5.encode(req.getNewPassword()));
        handlerUpdateBefore(entityDo, userId);
        dao.updateById(entityDo);
        return req;
    }

    @Override
    public SingleResult bindKey(UserBindReq req, Long userId) {
        LambdaQueryWrapper<ShopDo> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(ShopDo::getId, req.getShopId());
        ShopDo shopDo = shopDao.selectOne(wrapper);
        if (shopDo == null) {
            throw new BizExceptionI18(SysConstant.User_Error_BingKey);
        }
        if (req.getPlatformId().equals(DicBusinessItemConstant.amazon)) {
//            shopDo.setAmazonSellerId(req.getKey());
//            shopDo.setAmazonToken(req.getValue());
            return SingleResult.success("请求成功", authorizeNow(req, 16L, userId));
        }
        //对接tiktok文档
        else if(req.getPlatformId().equals(DicBusinessItemConstant.tiktok))
        {     //将req.getShopId存放到缓存中
            redisTemplate.opsForValue().set(TiktokShopId,req.getShopId());
            if(req.getCode()==null){
            return SingleResult.success("请求成功", generateAuthUrl());
            }
            else {
                return SingleResult.success("请求成功", getAccessToken2(req.getCode()));
            }

        }
        else if (req.getPlatformId().equals(DicBusinessItemConstant.rakuton)) {
            shopDo.setRakutenLicense(req.getKey().trim());
            shopDo.setRakutenSecret(req.getValue().trim());
            shopDo.setExpirationTime(null);
        } else if (req.getPlatformId().equals(DicBusinessItemConstant.qooTen)) {
            shopDo.setQootenId(req.getId().trim());
            shopDo.setQootenKey(req.getValue().trim());
            shopDo.setQootenPwd(req.getKey().trim());
        }
        shopDo.setUpdateBy(userId);
        shopDo.setKeyStatus(1);
        shopDo.setUpdateTime(new Date());
        shopDao.updateById(shopDo);
        return SingleResult.success("绑定成功", req);
    }

  /*  private String handleCode(UserBindReq req) {
        String code = req.getCode();
        if (code == null) {
            redisTemplate.opsForValue().set("tiktok_shop_id",req.getShopId());
            String result = generateAuthUrl();
            return result;
        }else{
            redisTemplate.opsForValue().set("tiktok_shop_id",req.getShopId());
            SingleResult<AuthResponse> accessToken2 = getAccessToken2(req.getCode());

        }
    }*/



    public String generateAuthUrl() {

        System.out.println("test");
        return "https://auth.tiktok-shops.com/api/v2/authorize?" +
                "app_key=" + clientId +
                "&redirect_uri=" + redirectUri +
                "&response_type=code" +
                "&scope=seller.basic.read seller.order.read seller.payment.read seller.product.write seller.account.read";

    }
   /* public GetOrderListResponse getOrder(String accessToken, String shopCipher)throws Exception  {

        CustomApiClient defaultClient = new CustomApiClient();
        defaultClient.setAppkey(appKey);
        defaultClient.setSecret(clientSecret);
        defaultClient.setBasePath("https://open-api.tiktokglobalshop.com");
        OrderV202309Api apiInstance = new OrderV202309Api(defaultClient);
        GetOrderListRequestBody getOrderListRequestBody = new GetOrderListRequestBody();
            getOrderListRequestBody.setOrderStatus("UNPAID");
            getOrderListRequestBody.setCreateTimeGe(1623812664L);
            getOrderListRequestBody.setCreateTimeLt(1623812664L);
            getOrderListRequestBody.setUpdateTimeGe(1623812664L);
            getOrderListRequestBody.setUpdateTimeLt(1623812664L);
            getOrderListRequestBody.setShippingType("TIKTOK");
            getOrderListRequestBody.setBuyerUserId("7213489962827123654");
            getOrderListRequestBody.setIsBuyerRequestCancel(false);
            List<String> getOrderListRequestBodyWarehouseIdsList = new ArrayList<>(Arrays.asList("7000714532876273888","7000714532876273666"));
            getOrderListRequestBody.setWarehouseIds(getOrderListRequestBodyWarehouseIdsList);
        GetOrderListResponse result = apiInstance.order202309OrdersSearchPost(20, accessToken, "application/json", "ASC", "", "create_time",shopCipher, getOrderListRequestBody);
        GetOrderListResponseData data = result.getData();

        System.out.println("--------------------GET ORDER------------------------");
        System.out.println(result);

        return result;
    }*/

    private GetOrderListResponse getOrder(String accessToken, String shopCipher, Long updateSince, String orderStatus) throws Exception {
        CustomApiClient defaultClient = new CustomApiClient();
        defaultClient.setAppkey(appKey);
        defaultClient.setSecret(clientSecret);
        defaultClient.setBasePath("https://open-api.tiktokglobalshop.com");
        OrderV202309Api apiInstance = new OrderV202309Api(defaultClient);
        GetOrderListRequestBody getOrderListRequestBody = new GetOrderListRequestBody();

        if (updateSince != null) {
            getOrderListRequestBody.setUpdateTimeGe(updateSince); // 只获取更新时间大于等于的时间段
        }

        // 设置订单状态
        if (orderStatus != null && !orderStatus.isEmpty()) {
            getOrderListRequestBody.setOrderStatus(orderStatus);
        }

        return apiInstance.order202309OrdersSearchPost(
                20, accessToken, "application/json", "ASC", "", "create_time", shopCipher, getOrderListRequestBody);
    }


    public List<GetOrderListResponse> getAllOrdersByStatuses(String accessToken, String shopCipher, Long updateSince) throws Exception {
        List<String> statuses = Arrays.asList(
                "UNPAID"
               /* "ON_HOLD",
                "AWAITING_SHIPMENT",
                "PARTIALLY_SHIPPING",
                "AWAITING_COLLECTION",
                "IN_TRANSIT",
                "DELIVERED",
                "COMPLETED",
                "CANCELLED"*/
        );

        List<GetOrderListResponse> allResponses = new ArrayList<>();

        for (String status : statuses) {
            GetOrderListResponse response = getOrder(accessToken, shopCipher, updateSince, status);
            allResponses.add(response);
        }

        return allResponses;
    }

//restTemplate替换为OKHttp
   /* public SingleResult<AuthResponse> getAccessToken(String authCode) {
        String tokenUrl = "https://auth.tiktok-shops.com/api/v2/token/get?" +
                "app_key=" + clientId +
                "&app_secret=" + clientSecret +
                "&auth_code=" + authCode +
                "&grant_type=authorized_code";
        Object obj = redisTemplate.opsForValue().get(TiktokShopId);
        if (obj == null) {
            throw new BizExceptionI18("tiktok.shop.id.not.found");
        }
        Long shopId = ((Number) obj).longValue(); // 支持 Integer、Long、Double 等所有 Number 子类

        // 使用 RestTemplate 发起 GET 请求
        ResponseEntity<String> responseEntity = restTemplate.getForEntity(tokenUrl, String.class);

        if (responseEntity.getStatusCode().is2xxSuccessful()) {
            try {
                ObjectMapper objectMapper = new ObjectMapper();
                JsonNode jsonNode = objectMapper.readTree(responseEntity.getBody());

                // 解析 data 字段为 AuthResponse 对象
                AuthResponse authResponse = objectMapper.treeToValue(jsonNode.get("data"), AuthResponse.class);
                if (authResponse == null) {
                    return SingleResult.failure("Failed to parse response: " + responseEntity.getBody());
                }


                //使用lambdaquery查询id相同的shop,将aceestoken插入数据库中
                LambdaQueryWrapper<ShopDo> wrapper = new LambdaQueryWrapper<>();
                wrapper.eq(ShopDo::getId, shopId);
                ShopDo shopDo = shopDao.selectOne(wrapper);

                if (shopDo == null) {
                    // 记录日志，方便排查问题
                    throw new BizExceptionI18(SysConstant.User_Error_BingKey);
                }

                //  将access_token和refresh_token保存到redis中过期时间为各自的过期时间,就是说过期时间到redis就删除
                long currentTimestamp = System.currentTimeMillis()/1000;
                Long accessTokenExpireIn = authResponse.getAccess_token_expire_in();
                Long refreshTokenExpireIn = authResponse.getRefresh_token_expire_in();
               Long tokenExpireIn = accessTokenExpireIn-currentTimestamp;
              Long refreshExpireIn = refreshTokenExpireIn-currentTimestamp;

                String accessTokenKey = TiktokAccessToken + shopId;
                String refreshTokenKey = TiktokRefreshToken + shopId;
                String accessTokenExpireKey = TiktokExpiresIn+shopId;
                String refreshTokenExpireKey = TiktokRefreshExpiresIn+shopId;
                redisTemplate.opsForValue().set(accessTokenKey, authResponse.getAccess_token());
                redisTemplate.opsForValue().set(refreshTokenKey, authResponse.getRefresh_token());
                redisTemplate.opsForValue().set(accessTokenExpireKey, authResponse.getAccess_token_expire_in());
                redisTemplate.opsForValue().set(refreshTokenExpireKey, authResponse.getRefresh_token_expire_in());
                redisTemplate.expire(accessTokenKey, tokenExpireIn, TimeUnit.SECONDS);
                redisTemplate.expire(refreshTokenKey, refreshExpireIn, TimeUnit.SECONDS);
                // 返回成功的结果
                authorizeShop(shopId);
                return SingleResult.success(authResponse);
            } catch (JsonProcessingException e) {
                // 处理 JSON 解析异常
                return SingleResult.failure("Failed to parse response: " + e.getMessage());
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        } else {
            // 请求失败时返回错误信息
            return SingleResult.failure("Failed to get access token, HTTP status: " + responseEntity.getStatusCodeValue());
        }
    }*/
public SingleResult<AuthResponse> getAccessToken(String authCode) {
    String tokenUrl = "https://auth.tiktok-shops.com/api/v2/token/get?" +
            "app_key=" + clientId +
            "&app_secret=" + clientSecret +
            "&auth_code=" + authCode +
            "&grant_type=authorized_code";

    Object obj = redisTemplate.opsForValue().get(TiktokShopId);
    if (obj == null) {
        throw new BizExceptionI18("tiktok.shop.id.not.found");
    }
    Long shopId = ((Number) obj).longValue();

    // 使用 OkHttp 发起 GET 请求
    OkHttpClient client = new OkHttpClient.Builder()
            .connectTimeout(30, TimeUnit.SECONDS)
            .readTimeout(30, TimeUnit.SECONDS)
            .writeTimeout(30, TimeUnit.SECONDS)
            .build();

    Request request = new Request.Builder()
            .url(tokenUrl)
            .build();

    try (Response response = client.newCall(request).execute()) {
        if (response.isSuccessful() && response.body() != null) {
            String responseBody = response.body().string();
            ObjectMapper objectMapper = new ObjectMapper();
            JsonNode jsonNode = objectMapper.readTree(responseBody);

            AuthResponse authResponse = objectMapper.treeToValue(jsonNode.get("data"), AuthResponse.class);
            if (authResponse == null) {
                return SingleResult.failure("Failed to parse response: " + responseBody);
            }

            LambdaQueryWrapper<ShopDo> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(ShopDo::getId, shopId);
            ShopDo shopDo = shopDao.selectOne(wrapper);
            if (shopDo == null) {
                throw new BizExceptionI18(SysConstant.User_Error_BingKey);
            }

            long currentTimestamp = System.currentTimeMillis() / 1000;
            Long accessTokenExpireIn = authResponse.getAccess_token_expire_in();
            Long refreshTokenExpireIn = authResponse.getRefresh_token_expire_in();
            long tokenExpireIn = accessTokenExpireIn - currentTimestamp;
            long refreshExpireIn = refreshTokenExpireIn - currentTimestamp;

            String accessTokenKey = TiktokAccessToken + shopId;
            String refreshTokenKey = TiktokRefreshToken + shopId;
            String accessTokenExpireKey = TiktokExpiresIn + shopId;
            String refreshTokenExpireKey = TiktokRefreshExpiresIn + shopId;

            redisTemplate.opsForValue().set(accessTokenKey, authResponse.getAccess_token(), tokenExpireIn, TimeUnit.SECONDS);
            redisTemplate.opsForValue().set(refreshTokenKey, authResponse.getRefresh_token(), refreshExpireIn, TimeUnit.SECONDS);
            redisTemplate.opsForValue().set(accessTokenExpireKey, authResponse.getAccess_token_expire_in());
            redisTemplate.opsForValue().set(refreshTokenExpireKey, authResponse.getRefresh_token_expire_in());

            authorizeShop(shopId);
            return SingleResult.success(authResponse);
        } else {
            return SingleResult.failure("Failed to get access token, HTTP status: " + (response.code()));
        }
    } catch (IOException e) {
        return SingleResult.failure("Request or parsing error: " + e.getMessage());
    } catch (Exception e) {
        throw new RuntimeException(e);
    }
}
//使用OKHttp替换restTemplate
    /*public SingleResult<AuthResponse> getAccessToken2(String authCode) {
        String tokenUrl = "https://auth.tiktok-shops.com/api/v2/token/get?" +
                "app_key=" + clientId +
                "&app_secret=" + clientSecret +
                "&auth_code=" + authCode +
                "&grant_type=authorized_code";
        Object obj = redisTemplate.opsForValue().get(TiktokShopId);
        if (obj == null) {
            throw new BizExceptionI18("tiktok.shop.id.not.found");
        }
        Long shopId = ((Number) obj).longValue(); // 支持 Integer、Long、Double 等所有 Number 子类

        // 使用 RestTemplate 发起 GET 请求
        ResponseEntity<String> responseEntity = restTemplate.getForEntity(tokenUrl, String.class);
        if (responseEntity.getStatusCode().is2xxSuccessful()) {
            try {
                ObjectMapper objectMapper = new ObjectMapper();
                JsonNode jsonNode = objectMapper.readTree(responseEntity.getBody());

                // 解析 data 字段为 AuthResponse 对象
                AuthResponse authResponse = objectMapper.treeToValue(jsonNode.get("data"), AuthResponse.class);
                String accessToken = authResponse.getAccess_token();
                String refreshToken = authResponse.getRefresh_token();
                //使用lambdaquery查询id相同的shop,将aceestoken插入数据库中
                LambdaQueryWrapper<ShopDo> wrapper = new LambdaQueryWrapper<>();
                wrapper.eq(ShopDo::getId, shopId);
                ShopDo shopDo = shopDao.selectOne(wrapper);

                if (shopDo == null) {
                    // 记录日志，方便排查问题
                    throw new BizExceptionI18(SysConstant.User_Error_BingKey);
                }
                //  将access_token和refresh_token保存到redis中过期时间为各自的过期时间,就是说过期时间到redis就删除
                long currentTimestamp = System.currentTimeMillis()/1000;
                Long accessTokenExpireIn = authResponse.getAccess_token_expire_in();
                Long refreshTokenExpireIn = authResponse.getRefresh_token_expire_in();
                Long tokenExpireIn = accessTokenExpireIn-currentTimestamp;
                Long refreshExpireIn = refreshTokenExpireIn-currentTimestamp;

                String accessTokenKey = TiktokAccessToken + shopId;
                String refreshTokenKey = TiktokRefreshToken + shopId;
                String accessTokenExpireKey = TiktokExpiresIn+shopId;
                String refreshTokenExpireKey = TiktokRefreshExpiresIn+shopId;
                redisTemplate.opsForValue().set(accessTokenKey, authResponse.getAccess_token());
                redisTemplate.opsForValue().set(refreshTokenKey, authResponse.getRefresh_token());
                redisTemplate.opsForValue().set(accessTokenExpireKey, authResponse.getAccess_token_expire_in());
                redisTemplate.opsForValue().set(refreshTokenExpireKey, authResponse.getRefresh_token_expire_in());
                redisTemplate.expire(accessTokenKey, tokenExpireIn, TimeUnit.SECONDS);
                redisTemplate.expire(refreshTokenKey, refreshExpireIn, TimeUnit.SECONDS);
                // 返回成功的结果
                authorizeShop(shopId);
                return SingleResult.success(authResponse);
            } catch (JsonProcessingException e) {
                // 处理 JSON 解析异常
                return SingleResult.failure("Failed to parse response: " + e.getMessage());
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        } else {
            // 请求失败时返回错误信息
            return SingleResult.failure("Failed to get access token, HTTP status: " + responseEntity.getStatusCodeValue());
        }
    }*/
public SingleResult<AuthResponse> getAccessToken2(String authCode) {
    String tokenUrl = "https://auth.tiktok-shops.com/api/v2/token/get?" +
            "app_key=" + clientId +
            "&app_secret=" + clientSecret +
            "&auth_code=" + authCode +
            "&grant_type=authorized_code";

    Object obj = redisTemplate.opsForValue().get(TiktokShopId);
    if (obj == null) {
        throw new BizExceptionI18("tiktok.shop.id.not.found");
    }
    Long shopId = ((Number) obj).longValue();

    // 使用 OkHttp 发起 GET 请求
    OkHttpClient client = new OkHttpClient.Builder()
            .connectTimeout(30, TimeUnit.SECONDS)
            .readTimeout(30, TimeUnit.SECONDS)
            .writeTimeout(30, TimeUnit.SECONDS)
            .build();

    Request request = new Request.Builder()
            .url(tokenUrl)
            .build();

    try (Response response = client.newCall(request).execute()) {
        if (response.isSuccessful() && response.body() != null) {
            String responseBody = response.body().string();
            ObjectMapper objectMapper = new ObjectMapper();
            JsonNode jsonNode = objectMapper.readTree(responseBody);

            AuthResponse authResponse = objectMapper.treeToValue(jsonNode.get("data"), AuthResponse.class);
            if (authResponse == null) {
                return SingleResult.failure("Failed to parse response: " + responseBody);
            }

            LambdaQueryWrapper<ShopDo> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(ShopDo::getId, shopId);
            ShopDo shopDo = shopDao.selectOne(wrapper);
            if (shopDo == null) {
                throw new BizExceptionI18(SysConstant.User_Error_BingKey);
            }

            long currentTimestamp = System.currentTimeMillis() / 1000;
            Long accessTokenExpireIn = authResponse.getAccess_token_expire_in();
            Long refreshTokenExpireIn = authResponse.getRefresh_token_expire_in();
            long tokenExpireIn = accessTokenExpireIn - currentTimestamp;
            long refreshExpireIn = refreshTokenExpireIn - currentTimestamp;

            String accessTokenKey = TiktokAccessToken + shopId;
            String refreshTokenKey = TiktokRefreshToken + shopId;
            String accessTokenExpireKey = TiktokExpiresIn + shopId;
            String refreshTokenExpireKey = TiktokRefreshExpiresIn + shopId;

            redisTemplate.opsForValue().set(accessTokenKey, authResponse.getAccess_token(), tokenExpireIn, TimeUnit.SECONDS);
            redisTemplate.opsForValue().set(refreshTokenKey, authResponse.getRefresh_token(), refreshExpireIn, TimeUnit.SECONDS);
            redisTemplate.opsForValue().set(accessTokenExpireKey, authResponse.getAccess_token_expire_in());
            redisTemplate.opsForValue().set(refreshTokenExpireKey, authResponse.getRefresh_token_expire_in());

            authorizeShop(shopId);
            return SingleResult.success(authResponse);
        } else {
            return SingleResult.failure("Failed to get access token, HTTP status: " + response.code());
        }
    } catch (IOException e) {
        return SingleResult.failure("Request or parsing error: " + e.getMessage());
    } catch (Exception e) {
        throw new RuntimeException(e);
    }
}


    @Transactional(rollbackFor = Exception.class)
    public GetAuthorizedShopsResponse authorizeShop(Long shopId) throws Exception {
        CustomApiClient defaultClient = new CustomApiClient();
        defaultClient.setAppkey(appKey);
        defaultClient.setSecret(clientSecret);
        defaultClient.setBasePath("https://open-api.tiktokglobalshop.com");
        AuthorizationV202309Api apiInstance = new AuthorizationV202309Api(defaultClient);

        ShopDo shopDo = shopDao.selectById(shopId);
        if (shopDo == null) {
            throw new BizExceptionI18(SysConstant.Shop_NotExist);
        }
        String accessTokenKey = TiktokAccessToken + shopId;
        String tiktokAccessToken = (String) redisTemplate.opsForValue().get(accessTokenKey);

        GetAuthorizedShopsResponse result = apiInstance.authorization202309ShopsGet(tiktokAccessToken, "application/json");
        GetAuthorizedShopsResponseData data = result.getData();

        if (data == null || CollectionUtils.isEmpty(data.getShops())) {
            throw new BizExceptionI18("tiktok.authorized.shops.empty");
        }

        //获取cipher
        String cipher = data.getShops().stream()
                .map(GetAuthorizedShopsResponseDataShops::getCipher)
                .filter(StringUtils::isNotBlank)
                .findFirst()
                .orElseThrow(() -> new BizExceptionI18("tiktok.shop.cipher.not.found"));
        Long currentTime = System.currentTimeMillis() / 1000;
        String shopCipherKey = TiktokShopCipher + shopId;
        String refreshTokenKey = TiktokRefreshToken + shopId;
        String expireTime = TiktokExpiresIn + shopId;
        Object obj = redisTemplate.opsForValue().get(expireTime);

        if (obj != null && obj instanceof Number) {
            Long accessTokenExpireIn = ((Number) obj).longValue();
            redisTemplate.opsForValue().set(shopCipherKey, cipher, accessTokenExpireIn - currentTime, TimeUnit.SECONDS);
        } else {
            redisTemplate.opsForValue().set(shopCipherKey, cipher, 7, TimeUnit.DAYS);
        }


        String newRefreshToken = (String) redisTemplate.opsForValue().get(refreshTokenKey);
        log.info("Updating shop cipher: {} -> {}", shopId, cipher);
        // 更新数据库
        shopDo.setShopCipher(cipher);
        shopDo.setTiktokAccessToken(tiktokAccessToken);
        shopDo.setTiktokRefreshToken(newRefreshToken);
        shopDao.updateById(shopDo);

        return result;
    }


    private void getOrderList(String tiktokAccessToken, String cipher,Long shopId) throws ApiException {
        CustomApiClient defaultClient = new CustomApiClient();
        defaultClient.setAppkey(appKey);
        defaultClient.setSecret(clientSecret);
        defaultClient.setBasePath("https://open-api.tiktokglobalshop.com");
        OrderV202309Api apiInstance = new OrderV202309Api(defaultClient);
        GetOrderListRequestBody getOrderListRequestBody = new GetOrderListRequestBody();
          /*  getOrderListRequestBody.setOrderStatus("UNPAID");
            getOrderListRequestBody.setCreateTimeGe(1623812664L);
            getOrderListRequestBody.setCreateTimeLt(1623812664L);
            getOrderListRequestBody.setUpdateTimeGe(1623812664L);
            getOrderListRequestBody.setUpdateTimeLt(1623812664L);
            getOrderListRequestBody.setShippingType("TIKTOK");
            getOrderListRequestBody.setBuyerUserId("7213489962827123654");
            getOrderListRequestBody.setIsBuyerRequestCancel(false);
            List<String> getOrderListRequestBodyWarehouseIdsList = new ArrayList<>(Arrays.asList("7000714532876273888","7000714532876273666"));
            getOrderListRequestBody.setWarehouseIds(getOrderListRequestBodyWarehouseIdsList);*/

       /* ShopDo shopDo = shopDao.selectById(shopId);
        String accessToken = shopDo.getTiktokAccessToken();
        String shopCipher = shopDo.getShopCipher();*/
        GetOrderListResponse result = apiInstance.order202309OrdersSearchPost(20, tiktokAccessToken, "application/json", "ASC", "", "create_time",cipher, getOrderListRequestBody);
        List<GetOrderListResponseDataOrders> orders = result.getData().getOrders();
        List<TiktokOrderVO> orderList=new ArrayList<>();
        List<TiktokOrderDo> tiktokOrderDos=new ArrayList<>();
        List<TiktokOrderPackageDo> tiktokOrderPackageDos=new ArrayList<>();
        List<TiktokOrderLineItemDo> tiktokOrderLineItemDos=new ArrayList<>();
        orders.forEach(order -> {
            String orderId = order.getId();
            TiktokOrderVO orderVO=new TiktokOrderVO();
            TiktokOrderDo tiktokOrderDo=new TiktokOrderDo();
            BeanUtils.copyProperties(order,tiktokOrderDo);
            tiktokOrderDo.setShopId(shopId);
            List<GetOrderListResponseDataOrdersPackages> packages = order.getPackages();
            List<GetOrderListResponseDataOrdersLineItems> lineItems = order.getLineItems();
            for (GetOrderListResponseDataOrdersPackages aPackage : packages) {
                TiktokOrderPackageDo tiktokOrderPackageDo=new TiktokOrderPackageDo();
                tiktokOrderPackageDo.setOrderId(orderId);
                tiktokOrderPackageDo.setPackageId(aPackage.getId());
                tiktokOrderPackageDos.add(tiktokOrderPackageDo);
            }
            for (GetOrderListResponseDataOrdersLineItems lineItem : lineItems) {
                TiktokOrderLineItemDo tiktokOrderLineItemDo=new TiktokOrderLineItemDo();
                tiktokOrderLineItemDo.setOrderId(orderId);
                BeanUtils.copyProperties(lineItem,tiktokOrderLineItemDo);
                tiktokOrderLineItemDos.add(tiktokOrderLineItemDo);
            }



            tiktokOrderDos.add(tiktokOrderDo);

            BeanUtils.copyProperties(order,orderVO);
            orderVO.setShopId(shopId);
            orderList.add(orderVO);
        });

        System.out.println("---------------------------------------------");
        System.out.println(orderList);
        System.out.println("---------------------------------------------");
        System.out.println("---------------------------------------------");
        System.out.println(tiktokOrderLineItemDos);
        System.out.println("---------------------------------------------");
        System.out.println("---------------------------------------------");
        System.out.println(tiktokOrderDos);
        //先将数据库中数据删除
        tiktokOrderDao.deleteAll();
        //批量插入mapper层
        tiktokOrderDao.insertBatch(tiktokOrderDos);
        tiktokOrderPackageDao.deleteAll();
        tiktokOrderPackageDao.insertBatch(tiktokOrderPackageDos);
         tiktokOrderLineItemDao.insertBatch(tiktokOrderLineItemDos);
        System.out.println("---------------------------------------------");
        System.out.println(result);
    }



    private String authorizeComplete(String amazon_callback_uri, String amazon_state, String selling_partner_id) {
        return amazon_callback_uri + "?" + "";
    }

    //编辑校验
    private void updateCheck(Object req) {

    }

    /**
     * 返回给前端跳转亚马逊的url（授权页面）
     */
//    @Override
    public String authorizeNow(UserBindReq req, Long marketPlaceId, Long userId) {

        String state = UUID.randomUUID().toString();
        //放入缓存
        redisTemplate.opsForValue().set(AUTHORIZESTATEKEY + userId, state, 3000, TimeUnit.SECONDS);
        redisTemplate.opsForValue().set(state, req.getShopId(), 3000, TimeUnit.SECONDS);
        Map paramMap = new HashMap();
        paramMap.put("state", state);
        paramMap.put("application_id", GlobalConstants.amazonSecret);
        String url = "";
        if (StringUtils.isNotBlank(req.getAmazon_callback_uri())
                && StringUtils.isNotBlank(req.getAmazon_state())
                && StringUtils.isNotBlank(req.getSelling_partner_id())) {
            url = req.getAmazon_callback_uri() + "?amazon_state=" + URLEncoder.encode(req.getAmazon_state()) + "&state=" + state + "&redirect_uri=" + GlobalConstants.AmazonSPRedirectURL;
        } else {
            url = ("Seller".equals(req.getAmazonSellerType()) ? GlobalConstants.AmazonSPURL : GlobalConstants.AmazonSPURL2) + "apps/authorize/consent?" + "application_id=" + GlobalConstants.amazonAppId + "&state=" + state + "&redirect_uri=" + GlobalConstants.AmazonSPRedirectURL;
        }
//        url += "&version=beta";
        return url;
    }

    @Override
    public SingleResult getAuthorizeMsg(Long shopId, Map<String, String> map, Long userId) {
        //验证state值
//        Object state = redisTemplate.opsForValue().get(AUTHORIZESTATEKEY + userId);
//        if (state == null || map.get("state") == null || !state.toString().equals(map.get("state"))) {
//            throw new BizException("授权超时,请重试");
//        }
        if (null == shopId) {
            Object value = redisTemplate.opsForValue().get(map.get("state"));
            if (value == null) {
                throw new BizExceptionI18(SysConstant.Shop_NotExist);
            }
            shopId = Long.parseLong(value.toString());
        }
        String sellingPartnerId = map.get("selling_partner_id");
        String mws_auth_token = map.get("mws_auth_token");

        //判断 sellingPartnerId 唯一性 todo


        //您的应用程序用 LWA 授权码交换 LWA 刷新令牌
        Map paramMap = new HashMap();
        paramMap.put("grant_type", "authorization_code");
        paramMap.put("code", map.get("spapi_oauth_code"));
        paramMap.put("client_id", GlobalConstants.AmzSpClientId);
        paramMap.put("client_secret", GlobalConstants.AmzSpClientSecret);
        paramMap.put("redirect_uri", GlobalConstants.AmazonSPRedirectURL);

        ShopDo shopDo = shopDao.selectById(shopId);
        if (shopDo == null) {
            throw new BizExceptionI18(SysConstant.Shop_NotExist);
        }
        String body = null;
        try {
            body = AmazonUtil.spAPidoPOST("https://api.amazon.com/auth/o2/token", "", "", paramMap, JSON.toJSONString(paramMap));
        } catch (Exception e) {
            e.printStackTrace();
        }
        System.out.println("店铺绑定亚马逊：" + shopId + "，body:" + body);
        if (body == null) {
            throw new BizExceptionI18(SysConstant.User_Auth_Error);
        }
        JSONObject jsonObject = JSONObject.parseObject(body);
        if (jsonObject == null || jsonObject.getString("refresh_token") == null) {
            throw new BizExceptionI18(SysConstant.User_Auth_Error);
        }

        shopDo.setAmazonSellerId(sellingPartnerId);
        shopDo.setAmazonToken(mws_auth_token);
        shopDo.setAmzSpLwa(jsonObject.getString("refresh_token"));
//        shopDo.setShopAuthorizeState(1L);
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(new Date());
        calendar.add(Calendar.YEAR, 1);
//        shopDo.setExpirationTime(calendar.getTime());
        shopDao.updateById(shopDo);

        redisTemplate.opsForValue().set(AMZACCESSTOKEN + shopDo.getId(), jsonObject.getString("access_token"), 3000, TimeUnit.SECONDS);
        return SingleResult.success();
    }

    //做修改之前要执行的业务定制处理
    private void handlerUpdateBefore(UserDo entityDo, Long userId) {
        entityDo.setUpdateBy(userId);
        entityDo.setUpdateTime(new Date());
    }


    @Override
    public int delete(Long id, Long userId) {
        UserDo entityDo = dao.selectById(id);
        handlerDeleteBefore(entityDo, userId);
        dao.updateById(entityDo);
        dao.updateById(entityDo);
        return dao.deleteById(id);
    }

    //做删除之前要执行的业务定制处理
    private void handlerDeleteBefore(UserDo entityDo, Long userId) {
        entityDo.setDeleteBy(userId);
        entityDo.setDeleteTime(new Date());
    }

    @Override
    public SingleResult verificationCode() {
        Map map = VerificationCodeUtil.generateCode();
        String key = UUID.randomUUID().toString();
        redisTemplate.opsForValue().set("verificationCode:" + key, map.get("result"), 5 * 60, TimeUnit.SECONDS);
        map.remove("result");
        map.put("key", key);
        return SingleResult.success(map);
    }

    @Override
    public SingleResult getPhoneByAccount(String userAccount) {
        LambdaQueryWrapper<UserDo> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(UserDo::getUserAccount, userAccount)
                .eq(UserDo::getUserType, 1);
        UserDo userDo = dao.selectOne(wrapper);
        if (userDo == null) {
            throw new BizExceptionI18(SysConstant.Login_Error_Notfound);
        }

        Map map = new HashMap();
        if (StringUtils.isNotBlank(userDo.getUserPhone())) {
            map.put("phone", PersonalInfoUtils.alipayAccountNo(userDo.getUserPhone(), 2));
        } else {
            map.put("phone", "该账号未绑定手机号，无法进行短信验证");
        }

        if (StringUtils.isNotBlank(userDo.getUserMail())) {
            map.put("mail", PersonalInfoUtils.alipayAccountNo(userDo.getUserMail(), 2));
        } else {
            map.put("mail", "该账号未绑定邮箱，无法进行邮箱验证");
        }

        map.put("userAccount", userDo.getUserAccount());

        return SingleResult.success(map);
    }


    @Override
    public SingleResult verificationCodeByPhone(SendMsgReq req) {
        LambdaQueryWrapper<UserDo> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(UserDo::getUserAccount, req.getUserAccount()).eq(UserDo::getUserType, 1);
        UserDo userDo = dao.selectOne(wrapper);
        if (userDo == null) {
            throw new BizExceptionI18(SysConstant.Login_Error_Notfound);
        }
        if (req.getType() == 1) {//短信验证
            CaptchaModeService captchaModeService = new PhoneSendMsgImpl(userDo, redisTemplate);
            Context context = new Context(captchaModeService);
            context.contextSend(SysConstant.DELETE_FLAG_TRUE);
        } else if (req.getType() == 2) {//邮箱验证
            CaptchaModeService captchaModeService = new MailSendMsgImpl(userDo, redisTemplate, mailSenderService);
            Context context = new Context(captchaModeService);
            context.contextSend(SysConstant.DELETE_FLAG_TRUE);
        }
        return SingleResult.success("验证码发送成功，请及时查收", null);
    }

    @Override
    public SingleResult verificationCodeCheck(CheckCodeReq req) {
        //校验验证码
        String code = (String) redisTemplate.opsForValue().get("phoneCode:" + req.getUserAccount());
        if (StringUtils.isBlank(code) || !(code.equals(req.getCode()))) {
            throw new BizExceptionI18(SysConstant.Login_VerCode_InCorrect);
        }

        //生成临时凭证 存入redis
        String key = UUID.randomUUID().toString();
        redisTemplate.opsForValue().set("phoneCodeKey:" + req.getUserAccount(), key, 30, TimeUnit.MINUTES);
        return SingleResult.success(key);
    }


    @Override
    public SingleResult findBackPassword(FindBackPasswordReq req) {
        String key = (String) redisTemplate.opsForValue().get("phoneCodeKey:" + req.getUserAccount());
        if (StringUtils.isBlank(key) || !(key.equals(req.getKey()))) {
            throw new BizExceptionI18(SysConstant.Session_Expired);
        }

        LambdaQueryWrapper<UserDo> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(UserDo::getUserAccount, req.getUserAccount())
                .eq(UserDo::getUserType, 1);
        UserDo userDo = dao.selectOne(wrapper);
        if (userDo == null) throw new BizExceptionI18(SysConstant.Login_Error_Notfound);


        MD5Util md5 = new MD5Util(SysConstant.SALT_STRING, "MD5");
        userDo.setUserPassword(md5.encode(req.getNewPassword()));
        dao.updateById(userDo);

        return SingleResult.success("密码修改成功!", null);
    }

    //查询明细之后要执行的业务定制处理
    private Object handlerDetailAfter(Object res) {
        return res;
    }

    @Override
    public SingleResult pageInit() {
        return SingleResult.success("");
    }

    @Override
    public List<UserListPageRes> getList(Map<String, String> map) {
        QueryWrapper<UserDo> wrapper = queryBuild(map);
        List<UserDo> list = this.list(wrapper);
        List<UserListPageRes> result = handlerListAfter(list);
        return result;
    }

    @Override
    public PageResult getListPage(Map<String, String> map) {
        QueryWrapper<UserDo> wrapper = queryBuild(map);
        IPage<UserDo> page = pageInit(map);
        page = this.page(page, wrapper);
        List<UserListPageRes> resList = handlerListAfter(page.getRecords());
        PageResult result = new PageResult(resList, (int) page.getCurrent(), (int) page.getSize(), (int) page.getTotal(), (int) page.getPages());
        return result;
    }

    //查询分页列表之后对列表数据的处理
    private List<UserListPageRes> handlerListAfter(List<UserDo> list) {
        List<UserListPageRes> result = new ArrayList<>();
        if (CollectionUtils.isNotEmpty(list)) {
            for (UserDo userDo : list) {
                UserListPageRes res = new UserListPageRes();
                res.setUserAccount(userDo.getUserAccount());
                res.setUserName(userDo.getUserName());
                res.setId(userDo.getId());
                res.setUserMail(userDo.getUserMail());
                res.setUserPhone(userDo.getUserPhone());
                RoleDo roleDo = roleDao.selectById(userDo.getRoleId());
                if (roleDo != null) {
                    res.setRoleName(roleDo.getRoleName());
                    res.setRoleId(roleDo.getId());
                }
                res.setShopId(userDo.getShopId());
                ShopDo shopDo = shopDao.selectById(userDo.getShopId());
                if (shopDo != null) {
                    res.setShopName(shopDo.getShopName());
                }
                res.setLastLoginTime(userDo.getLastLoginTime());

                result.add(res);
            }
        }
        return result;
    }


    private IPage<UserDo> pageInit(Map<String, String> map) {
        IPage<UserDo> page = new Page();
        page.setSize(StringUtils.isNotBlank(map.get("pageSize")) ? Long.parseLong(map.get("pageSize")) : 10);
        page.setCurrent(StringUtils.isNotBlank(map.get("current")) ? Long.parseLong(map.get("current")) : 1);
        return page;
    }

    private QueryWrapper<UserDo> queryBuild(Map<String, String> map) {
        QueryWrapper<UserDo> wrapper = new QueryWrapper<>();
        if (StringUtils.isNotBlank(map.get("keyword"))) {
            wrapper.eq("company_id", Long.parseLong(map.get("companyId")))
                    .and(i -> i.like("user_account", map.get("keyword"))
                            .or().like("user_name", map.get("keyword"))
                            .or().like("user_phone", map.get("keyword")));
        } else {
            wrapper.eq("company_id", Long.parseLong(map.get("companyId")));
        }
        if (StringUtils.isNotBlank(map.get("roleId"))) {
            wrapper.eq("role_id", map.get("roleId"));
        }
        return wrapper;
    }

    @Override
    public SingleResult shopifyGetAuthorization(Long shopId, Long companyId, String code, String
            session, String state, String host, String hmac, String shop, String timestamp) {
        ShopDo shopDo = shopDao.selectById(shopId);
        if (shopDo == null & state != null) {
            shopDo = new ShopDo();
            shopDo.setShopName(shop.split("\\.")[0]);
            shopDo.setPlatformId(DicBusinessItemConstant.Shopify);
            shopDo.setCompanyId(companyId);
            shopDo.setCreateTime(new Date());
            shopDo.setDeleteFlag(SysConstant.DELETE_FLAG_FALSE);
            shopDao.insert(shopDo);
            shopId = shopDo.getId();
        }
        StringBuilder data = new StringBuilder();
        if (StringUtils.isNotBlank(code)) {
            data.append("code=" + code);
        }
        if (StringUtils.isNotBlank(host)) {
            data.append("&");
            data.append("host=" + host);
        }
        if (StringUtils.isNotBlank(session)) {
            data.append("&");
            data.append("session=" + session);
        }
        if (StringUtils.isNotBlank(shop)) {
            data.append("&");
            data.append("shop=" + shop);
        }
        if (StringUtils.isNotBlank(state)) {
            data.append("&");
            data.append("state=" + state);
        }
        if (StringUtils.isNotBlank(timestamp)) {
            data.append("&");
            data.append("timestamp=" + timestamp);
        }
        if (data.toString().startsWith("&")) {
            data.replace(0, 1, "");
        }
//        if (true) return SingleResult.failure("504", "授权失败,请重试");
        String url;
        try {
            if (StringUtils.isBlank(code)) {
                if (!HmacUtil.HMACSHA256(data.toString(), GlobalConstants.ShopifySecret).equals(hmac))
                    return SingleResult.failure("auth.error");
                url = "https://" + shop + "/admin/oauth/authorize?" +
                        "client_id=" + GlobalConstants.ShopifyKey +
//                        "&scope=write_orders,read_locations,read_customers,read_fulfillments,write_fulfillments" +
                        "&scope=read_orders,write_orders,read_locations,read_fulfillments,write_fulfillments," +
                        "write_assigned_fulfillment_orders,write_merchant_managed_fulfillment_orders,write_third_party_fulfillment_orders,read_shopify_payments_payouts" +
                        "&redirect_uri=" + "https://www.cloudkinto.com/kinto/KeyBinding" +
                        "&state=" + System.currentTimeMillis() +
                        "&grant_options[]=value";
                System.out.println(url);
                return SingleResult.success(url);
            } else {
//                shopDo = shopDao.selectById(state.split("\\-")[1]);
//                if (shopDo == null) shopDo = shopDao.selectById(33);
                if (!HmacUtil.HMACSHA256(data.toString(), GlobalConstants.ShopifySecret).equals(hmac))
                    return SingleResult.failure("auth.error");
                url = "https://" + shop + "/admin/oauth/access_token";
                InetSocketAddress addr = new InetSocketAddress("127.0.0.1", 10809);
                Proxy proxy = new Proxy(Proxy.Type.HTTP, addr); // http 代理
                OkHttpClient.Builder client = OkHttpUtils.getUnsafeOkHttpClient().newBuilder();
                client.connectTimeout(60, TimeUnit.SECONDS)
                        .readTimeout(60, TimeUnit.SECONDS)
                        .writeTimeout(60, TimeUnit.SECONDS)
//                        .proxy(proxy)
                        .retryOnConnectionFailure(true);
                System.out.println(url);
                Map<String, String> params = new HashMap<>();
                params.put("client_id", GlobalConstants.ShopifyKey);
                params.put("client_secret", GlobalConstants.ShopifySecret);
                params.put("code", code);
                Request request = new Request.Builder()
                        .addHeader("Content-Type", "application/json;charset=utf-8")
                        .post(RequestBody.create(MediaType.get("application/json"), JSON.toJSONString(params)))
                        .url(url)
                        .build();
                Response response = null;
                String body = "";
                try {
                    response = client.build().newCall(request).execute();
                    body = response.body().string();
                    System.out.println(body);
                    //{
                    //    "access_token": "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",
                    //    "scope": "write_orders,read_customers"
                    //}
                    JSONObject jsonObject = JSON.parseObject(body);
                    ShopDo shopUpdate = shopDao.selectById(shopId);
                    shopUpdate.setShopifyToken(jsonObject.getString("access_token"));
                    shopUpdate.setShopifyHost(shop);
                    shopDao.updateById(shopUpdate);
                } catch (SocketException e) {
                    e.printStackTrace();
                    return SingleResult.failure("504", SysConstant.AUTH_FAILURE);
                } catch (IOException e) {
                    e.printStackTrace();
                    return SingleResult.failure(SysConstant.AUTH_FAILURE);
                }
                return SingleResult.success();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return SingleResult.failure(SysConstant.AUTH_FAILURE);
    }


    /**
     * Yahoo 用户授权第一步， 获取授权url，前端直接跳转到该页面 ,
     */
    @Override
    public String getYahooAuthorizeUrl(YahooAuthReq req, Long userId) {
        Long shopId = req.getShopId();
        String sellerId = req.getSellerId();
        String publicKey = req.getPublicKey();
        Integer signatureVersion = req.getSignatureVersion();
        String state = "cloudkinto" + TimeUtils.getCurrentDateFormat("yyyyMMddHHmmss") + "-" + shopId;
        //放入缓存
        redisTemplate.opsForValue().set(YAHOOAUTHORIZESTATEKEY + userId, state, 360, TimeUnit.SECONDS);
        redisTemplate.opsForValue().set(state, shopId, 360, TimeUnit.SECONDS);
        String authorizeUrl = "https://auth.login.yahoo.co.jp/yconnect/v2/authorization?client_id=" + YahooUtils.clientIdV2 + "&redirect_uri=" + redirectUri + "&response_type=code&scope=" + yahooScope + "&state=" + state;//生产
        LambdaUpdateWrapper<ShopDo> updateWrapper = new LambdaUpdateWrapper();
        updateWrapper.set(ShopDo::getYahooSellerId, sellerId);
        updateWrapper.set(ShopDo::getSecret, publicKey);
        updateWrapper.set(ShopDo::getSecretVersion, signatureVersion);
        updateWrapper.eq(ShopDo::getId, shopId);
        shopService.update(updateWrapper);
        return authorizeUrl;
        //授权页面，如果用户同意授权， 会返回一个code和state(我们传过去的)
        //错误会返回 error 和 error_description 和 error_code
    }

    /**
     * Yahoo 用户授权第二部 根据上一步返回的 code refreshToken(刷新令牌,有效期为 4 周)
     */
    @Override
    public String getYahooRefreshTokenByCode(Long shopId, String code, String state) {
        //验证code 和state值
        if (shopId == null || shopId == 0) {
            Object value = redisTemplate.opsForValue().get(state);
            if (value == null) {
                if (state.contains("-")) {
                    shopId = Long.parseLong(state.split("-")[1]);
                    if (shopId == null)
                        throw new BizExceptionI18(SysConstant.Shop_NotExist);
                }
            }
            shopId = Long.parseLong(value.toString());
        }
        ShopDo shopDo = shopDao.selectById(shopId);
        if (shopDo == null) {
            throw new BizExceptionI18(SysConstant.Shop_NotExist);
        }
//        if (true)
//            return "state=" + state + "&code=" + code + "shopId=" + shopId;
        Map paramMap = new HashMap<>();
//        grant_type=authorization_code&code=" + code + "&redirect_uri=" + redirectUri
        paramMap.put("grant_type", "authorization_code");
        paramMap.put("code", code);
        paramMap.put("redirect_uri", redirectUri);
        String body = null;//{"error":"unsupported_grant_type","error_description":"grant type in request is not supported by the authorization server"}
        try {
            body = YahooUtils.yahooDoPost("https://auth.login.yahoo.co.jp/yconnect/v2/token", shopDo.getYahooSellerId(), shopDo.getSecret(), shopDo.getSecretVersion(), paramMap);
        } catch (Exception e) {
            e.printStackTrace();
        }
        if (org.apache.commons.lang3.StringUtils.isBlank(body)) {
            throw new BizExceptionI18(SysConstant.Connect_Timeout);
        }
        JSONObject jsonObject = JSONObject.parseObject(body);
        if (org.apache.commons.lang3.StringUtils.isNotBlank(jsonObject.getString("error_description"))) {
            throw new BizException(jsonObject.getString("error_description"));
        }
        String access_token = jsonObject.getString("access_token");
        String token_type = jsonObject.getString("token_type");
        Long expires_in = jsonObject.getLong("expires_in");
        String refresh_token = jsonObject.getString("refresh_token");//有效期为 4 周。最大长度为 512 字节长的字符串
        String id_token = jsonObject.getString("id_token");
        if (org.apache.commons.lang3.StringUtils.isBlank(access_token) || expires_in == null || org.apache.commons.lang3.StringUtils.isBlank(refresh_token) || org.apache.commons.lang3.StringUtils.isBlank(id_token)) {
            throw new BizExceptionI18(SysConstant.User_Auth_Error);
        }
        //todo 验证 id_token
        //refresh_token 是长期令牌(4周) 后期保存到 t_shop表中 todo
        if (shopDo != null) {
            shopDo.setYahooRefreshToken(refresh_token);
//            shopDo.setYahooSellerId(sellerId);
            shopDao.updateById(shopDo);
        }
        redisTemplate.opsForValue().set(YAHOOACCESSTOKEN_USER + shopId, access_token, expires_in - 30, TimeUnit.SECONDS);
        redisTemplate.opsForValue().set(YAHOOREFRESH_TOKEN_USER + shopId, refresh_token, 3600 * 24 * 28L - 30, TimeUnit.SECONDS);

        if (shopDo != null) {
            Map consumerParam = new HashMap();
            consumerParam.put("shopId", shopId);
            consumerParam.put("shopName", shopDo.getShopName());
            //获取Yahoo sellerId
//            getYahooUserInfoApi(shopDo.getId());
        }

        return access_token;
    }

    /**
     * Yahoo用户刷新令牌 换取 用户访问令牌
     *
     * @return
     */
    @Override
    public String getYahooUserAccessToken(Long shopId) {
        Object accessToken = redisTemplate.opsForValue().get(YAHOOACCESSTOKEN_USER + shopId);
        if (accessToken != null) {
            return accessToken.toString();
        }
        //accessToken过期， 用refresh_token 换取 accessToken过期
        Object refresh_token = redisTemplate.opsForValue().get(YAHOOREFRESH_TOKEN_USER + shopId);
        ShopDo shopDo = shopDao.selectById(shopId);
        if (shopDo == null) {
            return "";
        }
        if (refresh_token == null && org.apache.commons.lang3.StringUtils.isBlank(shopDo.getYahooRefreshToken())) {//刷新令牌也过期了
            if (org.apache.commons.lang3.StringUtils.isBlank(shopDo.getYahooRefreshToken())) {
                return "";
            }
            LambdaUpdateWrapper<ShopDo> updateWrapper = new LambdaUpdateWrapper<>();
            updateWrapper.set(ShopDo::getYahooRefreshToken, null);
            updateWrapper.eq(ShopDo::getId, shopId);
            shopService.update(updateWrapper);
            log.debug("Yahoo 店铺:" + (shopDo != null ? shopDo.getShopName() : "") + "授权令牌过期，请重新授权");
            return "";
            //throw new BizException("Ebay 店铺:"+ (shopDo != null ? shopDo.getShopName() : "") +"授权令牌过期，请重新授权");
        }
        if (refresh_token == null) {
            refresh_token = shopDo.getYahooRefreshToken();
        }
        //refresh_token 含有特殊符号 需要转义一下 v^1.1#i^1#f^0#p^3#I^3#r^1#t^Ul4xMF83OkE2NUZFMTBENUZDOERBRkZEQUNFQjMxRTFBNjg3NzNFXzJfMSNFXjEyODQ=
        refresh_token = org.apache.commons.lang3.StringUtils.replace(refresh_token.toString(), "#", "%23");
        String body = null;
        Map paramMap = new HashMap<>();
//        grant_type=authorization_code&code=" + code + "&redirect_uri=" + redirectUri
        paramMap.put("grant_type", "refresh_token");
        paramMap.put("refresh_token", refresh_token);
        try {
            body = YahooUtils.yahooDoPost("https://auth.login.yahoo.co.jp/yconnect/v2/token", shopDo.getYahooSellerId(), shopDo.getSecret(), shopDo.getSecretVersion(), paramMap);
            //{"error":"invalid_grant","error_description":"the provided authorization refresh token is invalid or was issued to another client"}
        } catch (Exception e) {
            e.printStackTrace();
        }
        if (org.apache.commons.lang3.StringUtils.isBlank(body)) {
            throw new BizExceptionI18(SysConstant.Connect_Timeout);
        }
        JSONObject jsonObject = JSONObject.parseObject(body);
        String access_token = jsonObject.getString("access_token");
        if (org.apache.commons.lang3.StringUtils.isBlank(access_token)) {
            String error = jsonObject.getString("error_description");
            if (error.contains("the provided authorization refresh token is invalid or was issued to another client")) {//todo 验证 返回值
                //刷新令牌过期，去更改店铺的授权状态 已过期 todo rabbitmq去做
                LambdaUpdateWrapper<ShopDo> updateWrapper = new LambdaUpdateWrapper<>();
                updateWrapper.set(ShopDo::getYahooRefreshToken, null);
                updateWrapper.eq(ShopDo::getId, shopId);
                shopService.update(updateWrapper);
            }
            log.debug(org.apache.commons.lang3.StringUtils.isBlank(error) ? "获取用户访问令牌失败" : (shopDo != null ? "Yahoo店铺 " + shopDo.getShopName() + ":" : "") + error);
            return "";
            //throw new BizException(StringUtils.isBlank(error) ? "获取用户访问令牌失败" : (shopDo != null ? "Yahoo店铺 "+shopDo.getShopName()+":" : "")+error);
        }
        int expires_in = jsonObject.getInteger("expires_in");
        String token_type = jsonObject.getString("token_type");// User Access Token
        redisTemplate.opsForValue().set(YAHOOACCESSTOKEN_USER + shopId, access_token, expires_in - 30, TimeUnit.SECONDS);
        return access_token;
    }


    @Override
    public Map<String, Object> getYahooUserInfoApi(Long shopId) {
        String body = null;
        Map param = new HashMap<>();
//        param.put("callback", "success");//如果指定了 则以 Content-Type: text/javascript 形式返回响应。
        try {
            body = YahooUtils.yahooDoGet("https://userinfo.yahooapis.jp/yconnect/v2/attribute", getYahooUserAccessToken(shopId), param);
        } catch (Exception e) {
            e.printStackTrace();
        }
        Map<String, Object> result = new HashMap<>();
        if (org.apache.commons.lang3.StringUtils.isBlank(body)) {
            result.put("code", "FAIL");
            result.put("msg", "Yahoo获取用户信息api 连接超时");
            return result;
        }
        JSONObject jsonObject = JSONObject.parseObject(body);
        if (org.apache.commons.lang3.StringUtils.isNotBlank(jsonObject.getString("error_description"))) {
            result.put("code", "FAIL");
            result.put("msg", jsonObject.getString("error_description"));
            return result;
        } else {
            //获取成功 保存
            YahooUserInfo userInfo = JSONObject.parseObject(body, YahooUserInfo.class);
            ShopDo shopDo = shopDao.selectById(shopId);
            if (shopDo != null) {
                shopDo.setYahooSellerId(userInfo.getSub());
                shopDao.updateById(shopDo);
            } else {
                log.error("Yahoo getYahooUserInfoApi api 没有对应店铺,店铺id: " + shopId);
            }
            result.put("code", "SUCCESS");
        }
        return result;
    }

    /********************绑定公众号功能块*******************/


    /**
     * 创建临时带参数二维码
     * scene_id 场景Id  777:登录二维码场景id    888:绑定二维码场景id
     */
    @Override
    public String createTicket(Long userId) {
        //调用静态方法获取access_token
        String accessToken = getAccessToken();
        if (StringUtils.isBlank(accessToken)) {
            accessToken = getAccessToken();
        }
        TreeMap<String, String> params = new TreeMap<>();
        params.put("access_token", accessToken);
        // output data
        JsonObject data = new JsonObject();
        data.addProperty("action_name", "QR_SCENE");
        data.addProperty("expire_seconds", 300);
        JsonObject scene = new JsonObject();
        //只有登录才能获取到userId 所以有userId就是获取绑定二维码
        if (userId == null) {
            scene.addProperty("scene_id", "777");
        } else {
            scene.addProperty("scene_id", "888");
        }
        JsonObject actionInfo = new JsonObject();
        actionInfo.add("scene", scene);
        data.add("action_info", actionInfo);
        log.debug("二维码请求参数：" + data);
        String result = HttpUtil.doPost("https://api.weixin.qq.com/cgi-bin/qrcode/create?access_token=", params, data.toString());
        //调用微信接口返回的result是json格式 将json转为object
        String body = JSONObject.toJSONString(result);
        Object ob = JSON.parse(body);
        String s = ob.toString();
        log.debug("生成二维码返回数据：" + s);
        //add 2022 03 21
        JSONObject jb = JSONObject.parseObject(s);
        String errCode = jb.getString("errcode");
        if (StringUtils.isNotBlank(errCode)) {
            if ("40001".equals(errCode)) {
                redisTemplate.opsForValue().set("wx_token", null, 2, TimeUnit.HOURS);
            }
        }
        WechatQRCode qrCode = JSONObject.parseObject(s, WechatQRCode.class);
        Map map = new HashMap();
        //将userId存放redis中，当扫描绑定二维码时，和xml数据包里的openId一起存在本地数据库,时效【5分钟】
        if (userId != null) {
            map.put("userId", String.valueOf(userId));
            redisTemplate.opsForValue().set("wx_binding_ticket:" + qrCode.getTicket(), map, 5, TimeUnit.MINUTES);
        }
        //判断token是否被替换掉 替换掉拿新的token生成ticket
        if (StringUtils.isBlank(qrCode.getTicket())) {
            accessToken = getAccessToken();
            if (!type.equals("dev")) {
                String ticket = createTicket(userId);
                System.out.println("***********" + accessToken);
                return ticket;
            } else {
                return "二维码已失效";
            }
        } else {
            return qrCode == null ? "二维码已失效" : qrCode.getTicket();
        }
    }


    /**
     * type 区分二维码类型 0：普通二维码 1：绑定二维码
     * status:1 已扫描
     * eventKey含有777：关注二维码  含有888：绑定二维码
     */
    @Override
    public String scanningCode(String request) {
        try {
            JSONObject jsonObject = XmlUtils.xml2Json(request);
            JSONObject jb = jsonObject.getJSONObject("xml");
            if (jb == null) {
                throw new BizExceptionI18(SysConstant.User_Scanning_NoXml);
            }
            Map map = new HashMap();
            String ticket = jb.getString("Ticket");
            //未关注时，eventKey有前缀 qrscene_
            String eventKey = jb.getString("EventKey");
            //非事件操作 没有eventKey 即向公众号发送消息时
            if (StringUtils.isBlank(eventKey)) {
                return "success";
            }
            if (eventKey.contains("qrscene_")) {
                eventKey = eventKey.replace("qrscene_", "");
            }
            map.put("msgType", jb.getString("MsgType"));
            map.put("event", jb.getString("Event"));
            map.put("openId", jb.getString("FromUserName"));
            map.put("status", 1);
            //获取openId用于保存到本地数据库
            WxUserDo wxdo = wxUserDao.selectOne(new QueryWrapper<WxUserDo>().eq("openid", jb.getString("FromUserName")));
            WxUserDo wxUserDo = new WxUserDo();
            wxUserDo.setOpenid(jb.getString("FromUserName"));
            //关注二维码数据包
            if (eventKey.equals("777")) {
                map.put("type", 0);
                //获取微信xml数据包表示二维码已经扫描，将二维码ticket存在redis中，过期时间【5分钟】
                redisTemplate.opsForValue().set("wx_login_ticket:" + ticket, map, 5, TimeUnit.MINUTES);
                //判断openId在数据库中是否存在，存在更新，不存在插入
                if (wxdo != null) {
                    wxUserDo.setId(wxdo.getId());
                    wxUserDo.setUpdateTime(new Date());
                    wxUserDao.updateById(wxUserDo);
                } else {
                    wxUserDo.setCreateTime(new Date());
                    wxUserDao.insert(wxUserDo);
                }

                //判断是否扫码登录进入 成功则公众号通知用户  add 2022.2.25 这个if()只是用来处理登录成功微信通知功能
                if (redisTemplate.hasKey("wx_login_ticket:" + ticket)) {
                    Map map1 = (Map) redisTemplate.opsForValue().get("wx_login_ticket:" + ticket);
                    if (null != map1) {
                        //从redis中取openId，然后查到微信用户信息，然后取userId,再取到userName,userPassword
                        String openId = (String) map1.get("openId");
                        //redis序列化
                        Integer status = (Integer) map1.get("status");
                        if (status == 1) {
                            WxUserDo wxUserDo1 = wxUserDao.selectOne(new QueryWrapper<WxUserDo>().eq("openid", openId));
                            UserDo userDo = dao.selectById(wxUserDo1.getUserId());
                            if (userDo == null || userDo.getIsBinding() != 1) {
                                //进这一步说明用户没绑定
                                System.out.println("没有绑定");
                            } else {
                                //到这一步说明用户扫码登录成功进去系统了 公众号提示
                                JSONObject jb1 = new JSONObject();
                                jb1.put("ToUserName", wxUserDo.getOpenid());
                                jb1.put("FromUserName", "gh_92b42c38c948");
                                jb1.put("CreateTime", System.currentTimeMillis() / 1000);
                                jb1.put("MsgType", "text");
                                jb1.put("Content", "扫码登录成功！");
                                String s = XmlUtils.JsonToXml(jb1);
                                log.debug("********" + s);
                                System.err.println("*********" + s);
                                return s;
                            }
                        }
                    }
                }

            } else if (eventKey.equals("888")) {
                map.put("type", 1);
                if (redisTemplate.hasKey("wx_binding_ticket:" + ticket)) {
                    Map map1 = (Map) redisTemplate.opsForValue().get("wx_binding_ticket:" + ticket);
                    if (null != map1) {
                        //获取微信xml数据包表示二维码已经扫描，将二维码ticket存在redis中，过期时间【5分钟】
                        redisTemplate.opsForValue().set("wx_binding_ticket:" + ticket, map, 5, TimeUnit.MINUTES);
                        wxUserDo.setUserId(Long.valueOf((String) map1.get("userId")));
                        //判断openId在数据库中是否存在，存在更新，不存在插入
                        if (wxdo != null) {
                            wxUserDo.setId(wxdo.getId());
                            wxUserDo.setUpdateTime(new Date());
                            wxUserDao.updateById(wxUserDo);
                        } else {
                            wxUserDo.setCreateTime(new Date());
                            wxUserDao.insert(wxUserDo);
                        }
                        //扫描二维码就绑定了，将user表中的is_binding 更新为1
                        UserDo userDo = new UserDo();
                        userDo.setId(Long.valueOf((String) map1.get("userId")));
                        userDo.setIsBinding(1);
                        dao.updateById(userDo);

                        //绑定后发送绑定成功通知给用户    add 2022.2.25
                        JSONObject jb1 = new JSONObject();
                        jb1.put("ToUserName", wxUserDo.getOpenid());
                        jb1.put("FromUserName", "gh_92b42c38c948");
                        jb1.put("CreateTime", System.currentTimeMillis() / 1000);
                        jb1.put("MsgType", "text");
                        jb1.put("Content", "恭喜你，绑定成功！");
                        String s = XmlUtils.JsonToXml(jb1);
                        log.debug("********" + s);
                        System.err.println("*********" + s);
                        return s;
                    }
                } else {
                    return "二维码已失效！";
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return "success";
    }

    @Override
    public SingleResult whetherBindingScan(ScanningCodeRes req) {
        //判断缓存里是否有保存的ticket，若存在说明二维码已扫描，反之。
        if (redisTemplate.hasKey("wx_binding_ticket:" + req.getTicket())) {
            Map map = (Map) redisTemplate.opsForValue().get("wx_binding_ticket:" + req.getTicket());
            //从redis中取openId，然后查到微信用户信息，然后取userId,再取到userName,userPassword
            if (null != map) {
                Integer status = (Integer) map.get("status");
                if (status != null) {
                    if (status == 1) {
                        return SingleResult.success(true);
                    }
                }
            }
        }
        return SingleResult.success("二维码未扫描！");
    }


    /**
     * 根据appid和获取token 需要判断是否redis中wx_token是否存在
     */
    public String getAccessToken() {
        String accessToken = (String) redisTemplate.opsForValue().get("wx_token");
        if (StringUtils.isBlank(accessToken)) {
            String url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" + GlobalConstants.WX_APPID + "&secret=" + GlobalConstants.WX_APPSECRET;
            JsonObject accessTokenInfo = null;
            try {
                DefaultHttpClient httpClient = new DefaultHttpClient();
                HttpGet httpGet = new HttpGet(url);
                HttpResponse httpResponse = httpClient.execute(httpGet);
                HttpEntity httpEntity = httpResponse.getEntity();
                String response = EntityUtils.toString(httpEntity, "utf-8");
                //LOGGER.error("获取Token-------------------"+response);
                Gson token_gson = new Gson();

                accessTokenInfo = token_gson.fromJson(response, JsonObject.class);
                System.out.println("get accessTokenInfo success. [result={" + accessTokenInfo + "}]");

                accessToken = accessTokenInfo.get("access_token").toString().replaceAll("\"", "");
                //将accesstoken存放在redis中，如果没有就重新调用方法获取,token过期时间【2小时】
                redisTemplate.opsForValue().set("wx_token", accessToken, 2, TimeUnit.HOURS);

                return accessToken;
            } catch (Exception ex) {
                System.out.println("fail to request wechat user info. [error={" + ex + "}]");
            }
        } else {
            return accessToken;
        }
        return "请求出错！";
    }


    @Override
    public SingleResult getOmsBindingInfo(Long userId) {
        UserDo userDo = dao.selectById(userId);
        if (userDo == null) {
            throw new BizExceptionI18(SysConstant.Login_Error_Notfound);
        }
        Map map = new HashMap();
        map.put("omsUserName", userDo.getUserAccount());
        try {
//            String s = OkHttpUtils.okHttpRequest("https://erp.cangsoft.com/api/user/manager/getBindingInfoByOms", "POST", JSON.toJSONString(map));
            String s = OkHttpUtils.okHttpRequest("http://192.168.1.41:8088/api/user/manager/getBindingInfoByOms", "POST", JSON.toJSONString(map));
            SingleResult<String> singleResult = JSONObject.parseObject(s, SingleResult.class);
            if (singleResult.getCode().equals("200")) {
                return singleResult;
            } else {
                return singleResult;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        return SingleResult.failure(SysConstant.BIND_INFO_ERROR);
    }


    @Override
    public SingleResult setOmsBindingInfo(UserUpdateOmsReq req, Long userId) {
        Map map = new HashMap();
        map.put("erpUserName", req.getOmsUserName());
        MD5Util encoderMd5 = new MD5Util(SysConstant.SALT_STRING, "MD5");
        map.put("erpPassword", encoderMd5.encode(req.getOmsPassword()));
        UserDo userDo = dao.selectById(userId);
        if (userDo == null) {
            throw new BizExceptionI18(SysConstant.Login_Error_Notfound);
        }
        map.put("omsUserName", userDo.getUserAccount());
        map.put("omsPassword", userDo.getUserPassword());
        try {
//            String s = OkHttpUtils.okHttpRequest("https://erp.cangsoft.com/api/user/manager/setBindingInfoByOms", "POST", JSON.toJSONString(map));
            String s = OkHttpUtils.okHttpRequest("http://192.168.1.41:8088/api/user/manager/setBindingInfoByOms", "POST", JSON.toJSONString(map));
            SingleResult<JSONObject> singleResult = JSONObject.parseObject(s, SingleResult.class);
            if (singleResult.getCode().equals("200")) {
                JSONObject jsonObject = singleResult.getData();
                userDo.setErpUserId(Long.parseLong(jsonObject.getString("userId")));
                dao.updateById(userDo);
                map = new HashMap();
                map.put("username", req.getOmsUserName());
                map.put("token", jsonObject.getString("token"));
                return SingleResult.success(map);
            } else {
                return singleResult;
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
        return SingleResult.failure(SysConstant.SAVE_FAILURE);
    }

    @Override
    public Map<Long, String> getUserListMap(Long companyId) {
        Map<Long, String> collect = dao.selectList(new LambdaQueryWrapper<UserDo>().eq(companyId != null, UserDo::getCompanyId, companyId))
                .stream().collect(Collectors.toMap(UserDo::getId, UserDo::getUserName));
        return collect;
    }

}

